package com.yanqu.road.server.channelserver.manager.activity.washe.game;

import com.yanqu.road.entity.activity.washe.config.WasheConfig;
import com.yanqu.road.entity.activity.washe.config.WasheSceneConfig;
import com.yanqu.road.entity.activity.washe.eliminate.WasheBlock;
import com.yanqu.road.entity.activity.washe.eliminate.WasheBlockEffect;
import com.yanqu.road.entity.activity.washe.eliminate.WasheGameData;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateEffect;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateResult;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateRoundResult;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateShow;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateStageResult;
import com.yanqu.road.entity.activity.washe.eliminate.WasheUseSkillParam;
import com.yanqu.road.entity.activity.washe.game.WasheUserGameData;
import com.yanqu.road.entity.enums.washe.eWasheBlockEffectType;
import com.yanqu.road.entity.enums.washe.eWasheBlockType;
import com.yanqu.road.entity.enums.washe.eWasheColorType;
import com.yanqu.road.entity.enums.washe.eWasheDirectionType;
import com.yanqu.road.entity.enums.washe.eWasheEffectType;
import com.yanqu.road.entity.enums.washe.eWasheOperateType;
import com.yanqu.road.entity.enums.washe.eWasheSceneType;
import com.yanqu.road.server.protocol.GameErrorCode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

public class WasheSceneLogic {

    public static void turnChangeRefresh(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {
        if (gameData.getSceneId() == eWasheSceneType.ZhaoCaiJinBao.getType()) {
            scene_02_refresh(config, random, gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.GuiKeZhanBu.getType()) {
            scene_06_refresh(config, random, gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.HongYouQingHua.getType()) {
            scene_08_refresh(config, random, gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.DianShanLeiMing.getType()) {
            scene_09_refresh(config, random, gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.YiBenWanLi.getType()) {
            scene_10_refresh(config, random, gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.DunHuangFeiTian.getType()) {
            scene_11_refresh(config, random, gameData, result);
        }
    }

    public static void beginGameInit(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {
        if (gameData.getSceneId() == eWasheSceneType.LuoGuXuanTian.getType()) {
            scene_03_init(config, random, gameData);
        } else if (gameData.getSceneId() == eWasheSceneType.HuoYaoKuangHuan.getType()) {
            scene_04_init(config, random, gameData);
        } else if (gameData.getSceneId() == eWasheSceneType.JieJieGao.getType()) {
            scene_05_operateEnd(config, random, gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.BaiBaoXiang.getType()) {
            scene_07_init(config, random, gameData);
        } else if (gameData.getSceneId() == eWasheSceneType.HongYouQingHua.getType()) {
            scene_08_init(config, random, gameData);
        } else if (gameData.getSceneId() == eWasheSceneType.DianShanLeiMing.getType()) {
            scene_09_init(config, random, gameData);
        } else if (gameData.getSceneId() == eWasheSceneType.WuCaiBinFen.getType()) {
            scene_12_operateEnd(config, random, gameData, result, false);
        } else if (gameData.getSceneId() == eWasheSceneType.YanHuoKuangHuan.getType()) {
            scene_13_init(config, random, gameData);
        } else {
            turnChangeRefresh(config, random, gameData, result);
        }
    }

    public static void operateEnd(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {
        if (gameData.getSceneId() == eWasheSceneType.LuoGuXuanTian.getType()) {
            scene_03_operateEnd(config, random, gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.JieJieGao.getType()) {
            scene_05_operateEnd(config, random, gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.BaiBaoXiang.getType()) {
            scene_07_operateEnd(gameData, result);
        } else if (gameData.getSceneId() == eWasheSceneType.WuCaiBinFen.getType()) {
            scene_12_operateEnd(config, random, gameData, result, true);
        }
    }

    public static void afterSameColorEliminate(WasheConfig config, WasheGameData gameData, Set<WasheBlock> roundEliminateSet, WasheOperateStageResult stageResult, eWasheOperateType operateType) {
        if (gameData.getSceneId() == eWasheSceneType.DianShanLeiMing.getType()) {
            scene_09_afterSameColorEliminate(config, gameData, roundEliminateSet, stageResult, operateType);
        } else if (gameData.getSceneId() == eWasheSceneType.YiBenWanLi.getType()) {
            scene_10_afterSameColorEliminate(config, gameData, roundEliminateSet, stageResult, operateType);
        }
    }

    /**
     * @param gameData 里面有方块为null
     */
    public static void replaceDropBlock(WasheConfig config, Random random, WasheGameData gameData, List<WasheBlock> newDropList) {
        if (gameData.getSceneId() == eWasheSceneType.HuoYaoKuangHuan.getType()) {
            scene_04_replaceDrop(config, random, newDropList, gameData);
        } else if (gameData.getSceneId() == eWasheSceneType.BaiBaoXiang.getType()) {
            scene_07_replaceDrop(config, random, newDropList, gameData);
        } else if (gameData.getSceneId() == eWasheSceneType.HongYouQingHua.getType()) {
            scene_08_replaceDrop(config, random, newDropList, gameData);
        } else if (gameData.getSceneId() == eWasheSceneType.YanHuoKuangHuan.getType()) {
            scene_13_replaceDrop(config, random, newDropList, gameData);
        }
    }

    public static void eliminateEnd(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result, WasheUserGameData userGameData, int roomRound, int turnPlayer) {
        if (gameData.getSceneId() == eWasheSceneType.BaiBaoXiang.getType()) {
            scene_07_eliminateEnd(config, random, gameData, result, userGameData, roomRound, turnPlayer);
        }
    }


    // -------------------- 【回合切换刷新】 --------------------

    private static void scene_02_refresh(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.ZhaoCaiJinBao.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int addScore = paramList.get(0).intValue();
        int num = paramList.get(1).intValue();
        int color = paramList.get(2).intValue();

        List<List<WasheBlock>> blockList = gameData.getBlockList();

        // 可选方块
        List<WasheBlock> canRandomList = new ArrayList<>();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (block.getColor() == color && block.getBlockType().getValue() == eWasheBlockType.Normal.getValue()) {
                    canRandomList.add(block);
                }
            }
        }

        // 随机替换
        List<WasheBlock> changeList = new ArrayList<>();
        Collections.shuffle(canRandomList, random);
        for (int i = 0; i < num && i < canRandomList.size(); i++) {

            WasheBlockEffect effect = new WasheBlockEffect(eWasheBlockEffectType.AddScore);
            effect.setEffectValue(addScore);

            WasheBlock clone = canRandomList.get(i).clone();
            clone.setBlockType(eWasheBlockType.ZhaoCaiJinBao);
            clone.addEffect(effect);
            blockList.get(clone.getY()).set(clone.getX(), clone);

            changeList.add(clone);
        }

        // 添加效果
        if (!changeList.isEmpty()) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.ReplaceBlock);
            effect.setBlockList(changeList);
            result.addEffect(effect);
        }
    }

    private static void scene_05_operateEnd(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.JieJieGao.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int baseScore = paramList.get(0).intValue();
        int addScore = paramList.get(1).intValue();
        int boardMaxNum = paramList.get(2).intValue();
        int color = paramList.get(3).intValue();

        List<List<WasheBlock>> blockList = gameData.getBlockList();

        // 可选方块
        int haveNum = 0;
        List<WasheBlock> canRandomList = new ArrayList<>();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (block.getBlockType() == eWasheBlockType.JieJieGao) {
                    haveNum++;
                }
                if (block.getColor() == color && block.getBlockType().getValue() == eWasheBlockType.Normal.getValue()) {
                    canRandomList.add(block);
                }
            }
        }
        if (haveNum >= boardMaxNum) {
            return;
        }

        // 随机替换
        List<WasheBlock> changeList = new ArrayList<>();
        Collections.shuffle(canRandomList, random);
        for (int i = 0; i < boardMaxNum - haveNum && i < canRandomList.size(); i++) {

            WasheBlockEffect effect = new WasheBlockEffect(eWasheBlockEffectType.AddScore);
            effect.setEffectValue(baseScore + gameData.getScene05Count() * addScore);

            WasheBlock clone = canRandomList.get(i).clone();
            clone.setBlockType(eWasheBlockType.JieJieGao);
            clone.getEffectList().add(effect);
            blockList.get(clone.getY()).set(clone.getX(), clone);

            gameData.setScene05Count(gameData.getScene05Count() + 1);
            changeList.add(clone);
        }

        // 添加效果
        if (!changeList.isEmpty()) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.ReplaceBlock);
            effect.setBlockList(changeList);
            result.addEffect(effect);
        }
    }

    private static void scene_06_refresh(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.GuiKeZhanBu.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int num = paramList.get(0).intValue();
        int color = paramList.get(1).intValue();

        List<List<WasheBlock>> blockList = gameData.getBlockList();

        // 可选方块
        List<WasheBlock> canRandomList = new ArrayList<>();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (block.getColor() == color && block.getBlockType().getValue() == eWasheBlockType.Normal.getValue()) {
                    canRandomList.add(block);
                }
            }
        }

        // 随机替换
        List<WasheBlock> changeList = new ArrayList<>();
        Collections.shuffle(canRandomList, random);
        for (int i = 0; i < num && i < canRandomList.size(); i++) {

            WasheBlock clone = canRandomList.get(i).clone();
            clone.setBlockType(eWasheBlockType.GuiKeZhanBu);
            blockList.get(clone.getY()).set(clone.getX(), clone);

            changeList.add(clone);
        }

        // 添加效果
        if (!changeList.isEmpty()) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.ReplaceBlock);
            effect.setBlockList(changeList);
            result.addEffect(effect);
        }
    }

    private static void scene_08_refresh(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {
        int blue = result.getTurn() == 1 ? eWasheColorType.Red.getValue() : eWasheColorType.Blue.getValue();

        List<List<WasheBlock>> blockList = gameData.getBlockList();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (block.getBlockType() == eWasheBlockType.HongYouQingHua) {
                    block.setColor(blue);
                }
            }
        }
    }

    private static void scene_09_refresh(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.DianShanLeiMing.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int boardMaxNum = paramList.get(1).intValue();

        // 已有数量
        int haveNum = 0;
        for (Map<Integer, WasheBlock> map : gameData.getFrameMap().values()) {
            for (WasheBlock frame : map.values()) {
                if (frame.getBlockType() == eWasheBlockType.DianShanLeiMing) {
                    haveNum++;
                }
            }
        }
        if (haveNum >= boardMaxNum) {
            return;
        }

        // 随机生成框
        List<WasheBlock> changeList = new ArrayList<>();
        List<WasheBlock> randomFramePos = WasheFrameLogic.randomFramePos(gameData, random, boardMaxNum - haveNum);
        for (WasheBlock block : randomFramePos) {

            WasheBlock frame = WasheBlock.createFrame(block.getX(), block.getY(), eWasheBlockType.DianShanLeiMing);
            gameData.addFrame(frame);

            changeList.add(frame);
        }

        // 添加效果
        if (!changeList.isEmpty()) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.UpdateBlock);
            effect.setBlockList(changeList);
            result.addEffect(effect);
        }
    }

    private static void scene_10_refresh(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.YiBenWanLi.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int multi = paramList.get(0).intValue();
        int boardMaxNum = paramList.get(1).intValue();

        // 已有数量
        int haveNum = 0;
        for (Map<Integer, WasheBlock> map : gameData.getFrameMap().values()) {
            for (WasheBlock frame : map.values()) {
                if (frame.getBlockType() == eWasheBlockType.YiBenWanLi) {
                    haveNum++;
                }
            }
        }
        if (haveNum >= boardMaxNum) {
            return;
        }

        // 随机生成框
        List<WasheBlock> changeList = new ArrayList<>();
        List<WasheBlock> randomFramePos = WasheFrameLogic.randomFramePos(gameData, random, boardMaxNum - haveNum);
        for (WasheBlock block : randomFramePos) {

            WasheBlockEffect effect = new WasheBlockEffect(eWasheBlockEffectType.YiBenWanLi);
            effect.setEffectValue(multi);

            WasheBlock frame = WasheBlock.createFrame(block.getX(), block.getY(), eWasheBlockType.YiBenWanLi);
            frame.addEffect(effect);
            gameData.addFrame(frame);

            changeList.add(frame);
        }

        // 添加效果
        if (!changeList.isEmpty()) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.UpdateBlock);
            effect.setBlockList(changeList);
            result.addEffect(effect);
        }
    }

    private static void scene_11_refresh(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.DunHuangFeiTian.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int boardMaxNum = paramList.get(0).intValue();

        // 已有数量
        int haveNum = 0;
        for (Map<Integer, WasheBlock> map : gameData.getFrameMap().values()) {
            for (WasheBlock frame : map.values()) {
                if (frame.getBlockType() == eWasheBlockType.DuNHuangFeiTian) {
                    haveNum++;
                }
            }
        }
        if (haveNum >= boardMaxNum) {
            return;
        }

        // 随机生成框
        List<WasheBlock> changeList = new ArrayList<>();
        List<WasheBlock> randomFramePos = WasheFrameLogic.randomFramePos(gameData, random, boardMaxNum - haveNum);
        for (WasheBlock block : randomFramePos) {

            WasheBlock frame = WasheBlock.createFrame(block.getX(), block.getY(), eWasheBlockType.DuNHuangFeiTian);
            gameData.addFrame(frame);

            changeList.add(frame);
        }

        // 添加效果
        if (!changeList.isEmpty()) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.UpdateBlock);
            effect.setBlockList(changeList);
            result.addEffect(effect);
        }
    }


    // -------------------- 【初始化】 --------------------

    private static void scene_03_init(WasheConfig config, Random random, WasheGameData gameData) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.LuoGuXuanTian.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int initScore = paramList.get(0).intValue();

        // 中心位置
        List<List<WasheBlock>> blockList = gameData.getBlockList();
        List<WasheBlock> list = blockList.get(blockList.size() / 2);
        WasheBlock block = list.get(list.size() / 2);

        // 生成框
        WasheBlockEffect effect = new WasheBlockEffect(eWasheBlockEffectType.LuoGuXuanTian);
        effect.setEffectValue(initScore);
        WasheBlock frame = WasheBlock.createFrame(block.getX(), block.getY(), eWasheBlockType.LuoGuXuanTian);
        frame.addEffect(effect);
        gameData.addFrame(frame);
    }

    private static void scene_04_init(WasheConfig config, Random random, WasheGameData gameData) {
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.HuoYaoKuangHuan.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int initNum = paramList.get(0).intValue();

        // 可选格子
        List<WasheBlock> canRandomList = new ArrayList<>();
        List<List<WasheBlock>> blockList = gameData.getBlockList();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (block.getBlockType().getBigType() == eWasheBlockType.BIG_TYPE_NORMAL) {
                    canRandomList.add(block);
                }
            }
        }

        // 实际替换
        Collections.shuffle(canRandomList, random);
        for (int i = 0; i < initNum && i < canRandomList.size(); i++) {
            WasheBlock block = canRandomList.get(i);
            block.setBlockType(eWasheBlockType.HuoYaoKuangHuan);
        }
    }

    private static void scene_07_init(WasheConfig config, Random random, WasheGameData gameData) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.BaiBaoXiang.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int boardMaxNum = paramList.get(1).intValue();

        // 可选格子
        List<List<WasheBlock>> blockList = gameData.getBlockList();
        List<WasheBlock> topLineList = blockList.get(blockList.size() - 1).stream()
                .filter(item -> item.getBlockType().getBigType() == eWasheBlockType.BIG_TYPE_NORMAL)
                .collect(Collectors.toList());

        // 随机替换
        Collections.shuffle(topLineList, random);
        for (int i = 0; i < boardMaxNum; i++) {
            WasheBlock block = topLineList.get(i);
            block.setBlockType(eWasheBlockType.BaiBaoXiang);
            block.setColor(eWasheColorType.None.getValue());
        }
    }

    private static void scene_08_init(WasheConfig config, Random random, WasheGameData gameData) {
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.HongYouQingHua.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int initNum = paramList.get(0).intValue();

        // 可选方块
        List<WasheBlock> redList = new ArrayList<>();
        List<WasheBlock> blueList = new ArrayList<>();
        List<List<WasheBlock>> blockList = gameData.getBlockList();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (block.getBlockType().getBigType() != eWasheBlockType.BIG_TYPE_NORMAL) {
                    continue;
                }
                if (block.getColor() == eWasheColorType.Red.getValue()) {
                    redList.add(block);
                } else if (block.getColor() == eWasheColorType.Blue.getValue()) {
                    blueList.add(block);
                }
            }
        }

        // 随机替换
        Collections.shuffle(redList, random);
        Collections.shuffle(blueList, random);
        int totalNum = initNum * 2;
        int blueIndex = 0;
        int redIndex = 0;
        List<WasheBlock> changeList = new ArrayList<>();
        while (changeList.size() < totalNum && (blueIndex < blueList.size() || redIndex < redList.size())) { // 循环蓝色替换一个、红色替换一个，直到数量满足要求

            changeList.forEach(item -> item.setColor(eWasheColorType.Red.getValue()));
            while (changeList.size() < totalNum && blueIndex < blueList.size()) {
                WasheBlock block = blueList.get(blueIndex++);
                block.setColor(eWasheColorType.Red.getValue());
                if (WasheGameLogic.canSameColorEliminate(gameData.getBlockList(), block)) {
                    block.setColor(eWasheColorType.Blue.getValue());
                } else {
                    block.setBlockType(eWasheBlockType.HongYouQingHua);
                    changeList.add(block);
                    break;
                }
            }

            changeList.forEach(item -> item.setColor(eWasheColorType.Blue.getValue()));
            while (changeList.size() < totalNum && redIndex < redList.size()) {
                WasheBlock block = redList.get(redIndex++);
                block.setColor(eWasheColorType.Blue.getValue());
                if (WasheGameLogic.canSameColorEliminate(gameData.getBlockList(), block)) {
                    block.setColor(eWasheColorType.Red.getValue());
                } else {
                    block.setBlockType(eWasheBlockType.HongYouQingHua);
                    changeList.add(block);
                    break;
                }
            }
        }
        changeList.forEach(item -> item.setColor(eWasheColorType.None.getValue()));
    }

    private static void scene_09_init(WasheConfig config, Random random, WasheGameData gameData) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.DianShanLeiMing.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int initNum = paramList.get(0).intValue();

        List<WasheBlock> randomFramePos = WasheFrameLogic.randomFramePos(gameData, random, initNum);
        for (WasheBlock block : randomFramePos) {
            WasheBlock frame = WasheBlock.createFrame(block.getX(), block.getY(), eWasheBlockType.DianShanLeiMing);
            gameData.addFrame(frame);
        }
    }

    private static void scene_13_init(WasheConfig config, Random random, WasheGameData gameData) {
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.YanHuoKuangHuan.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int initNum = paramList.get(0).intValue();

        // 拿格子
        List<WasheBlock> canRandomList = new ArrayList<>();
        List<List<WasheBlock>> listList = gameData.getBlockList();
        for (List<WasheBlock> list : listList) {
            for (WasheBlock block : list) {
                if (block.getColor() != eWasheColorType.Red.getValue() && block.getColor() != eWasheColorType.Blue.getValue()
                        && block.getBlockType().getBigType() == eWasheBlockType.BIG_TYPE_NORMAL) {
                    canRandomList.add(block);
                }
            }
        }

        // 随机替换
        Collections.shuffle(canRandomList, random);
        for (int i = 0; i < initNum && i < canRandomList.size(); i++) {
            WasheBlock block = canRandomList.get(i);
            block.setBlockType(eWasheBlockType.YanHuoKuangHuan);
            block.setDirection(eWasheDirectionType.getType(random.nextInt(4) + 1));
        }
    }


    // -------------------- 【掉落方块】 --------------------

    private static void scene_04_replaceDrop(WasheConfig config, Random random, List<WasheBlock> dropList, WasheGameData gameData) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.HuoYaoKuangHuan.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int boardMaxNum = paramList.get(1).intValue();
        int ratio = paramList.get(2).intValue();
        int turnMaxNum = paramList.get(3).intValue();

        // 回合数量
        int scene04Count = gameData.getScene04Count();
        if (scene04Count >= turnMaxNum) {
            return;
        }

        // 已有数量
        int haveNum = 0;
        for (List<WasheBlock> list : gameData.getBlockList()) {
            for (WasheBlock block : list) {
                if (block != null) {
                    if (block.getBlockType() == eWasheBlockType.HuoYaoKuangHuan) {
                        haveNum++;
                    }
                }
            }
        }
        if (haveNum >= boardMaxNum) {
            return;
        }

        // 随机替换
        ArrayList<WasheBlock> canRandomList = new ArrayList<>(dropList);
        Collections.shuffle(canRandomList);
        int limitNum = Math.min(boardMaxNum - haveNum, turnMaxNum - scene04Count);
        int realNum = 0;
        for (WasheBlock block : canRandomList) {
            if (realNum >= limitNum) {
                break;
            }
            if (random.nextInt(1000) < ratio) {
                block.setBlockType(eWasheBlockType.HuoYaoKuangHuan);
                realNum++;
            }
        }
        // 修改数据
        gameData.setScene04Count(scene04Count + realNum);
    }

    private static void scene_07_replaceDrop(WasheConfig config, Random random, List<WasheBlock> dropList, WasheGameData gameData) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.BaiBaoXiang.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int boardMaxNum = paramList.get(1).intValue();
        int ratio = paramList.get(2).intValue();
        int turnMaxNum = paramList.get(3).intValue();

        // 回合数量
        int scene07Count = gameData.getScene07Count();
        if (scene07Count >= turnMaxNum) {
            return;
        }

        // 已有数量
        int haveNum = 0;
        List<List<WasheBlock>> blockList = gameData.getBlockList();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (block != null) {
                    if (block.getBlockType() == eWasheBlockType.BaiBaoXiang) {
                        haveNum++;
                    }
                }
            }
        }
        if (haveNum >= boardMaxNum) {
            return;
        }

        // 可随机方块
        List<WasheBlock> canRandomList = new ArrayList<>();
        int topY = blockList.size() - 1;
        for (WasheBlock block : dropList) {
            if (block.getY() == topY) {
                canRandomList.add(block);
            }
        }

        // 随机替换
        Collections.shuffle(canRandomList);
        int limitNum = Math.min(boardMaxNum - haveNum, turnMaxNum - scene07Count);
        int realNum = 0;
        for (WasheBlock block : canRandomList) {
            if (realNum >= limitNum) {
                break;
            }
            if (random.nextInt(1000) < ratio) {
                block.setBlockType(eWasheBlockType.BaiBaoXiang);
                block.setColor(eWasheColorType.None.getValue());
                realNum++;
            }
        }
        // 修改数据
        gameData.setScene04Count(scene07Count + realNum);
    }

    private static void scene_08_replaceDrop(WasheConfig config, Random random, List<WasheBlock> dropList, WasheGameData gameData) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.HongYouQingHua.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int boardMaxNum = paramList.get(1).intValue();
        int ratio = paramList.get(2).intValue();
        int turnMaxNum = paramList.get(3).intValue();

        // 回合数量
        int scene08Count = gameData.getScene08Count();
        if (scene08Count >= turnMaxNum) {
            return;
        }

        // 已有数量
        int haveNum = 0;
        for (List<WasheBlock> list : gameData.getBlockList()) {
            for (WasheBlock block : list) {
                if (block != null) {
                    if (block.getBlockType() == eWasheBlockType.HongYouQingHua) {
                        haveNum++;
                    }
                }
            }
        }
        if (haveNum >= boardMaxNum) {
            return;
        }

        // 拿格子
        List<WasheBlock> canRandomList = new ArrayList<>();
        for (WasheBlock block : dropList) {
            if (block.getColor() == eWasheColorType.Red.getValue() || block.getColor() == eWasheColorType.Blue.getValue()) {
                canRandomList.add(block);
            }
        }

        // 随机替换
        Collections.shuffle(canRandomList);
        int limitNum = Math.min(boardMaxNum - haveNum, turnMaxNum - scene08Count);
        int realNum = 0;
        for (WasheBlock block : canRandomList) {
            if (realNum >= limitNum) {
                break;
            }
            if (random.nextInt(1000) < ratio) {
                block.setBlockType(eWasheBlockType.HongYouQingHua);
                realNum++;
            }
        }

        // 修改数据
        gameData.setScene04Count(scene08Count + realNum);
    }

    private static void scene_13_replaceDrop(WasheConfig config, Random random, List<WasheBlock> dropList, WasheGameData gameData) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.YanHuoKuangHuan.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int boardMaxNum = paramList.get(0).intValue();
        int turnMaxNum = paramList.get(1).intValue();
        int ratio = paramList.get(2).intValue();

        // 回合数量
        int scene13Count = gameData.getScene13Count();
        if (scene13Count >= turnMaxNum) {
            return;
        }

        // 已有数量
        int haveNum = 0;
        for (List<WasheBlock> list : gameData.getBlockList()) {
            for (WasheBlock block : list) {
                if (block != null) {
                    if (block.getBlockType() == eWasheBlockType.YanHuoKuangHuan) {
                        haveNum++;
                    }
                }
            }
        }
        if (haveNum >= boardMaxNum) {
            return;
        }

        // 随机替换
        List<WasheBlock> canRandomList = new ArrayList<>(dropList);
        Collections.shuffle(canRandomList);
        int limitNum = Math.min(boardMaxNum - haveNum, turnMaxNum - scene13Count);
        int realNum = 0;
        for (WasheBlock block : canRandomList) {
            if (realNum >= limitNum) {
                break;
            }
            if (random.nextInt(1000) < ratio) {
                block.setBlockType(eWasheBlockType.YanHuoKuangHuan);
                block.setDirection(eWasheDirectionType.getType(random.nextInt(4) + 1));
                realNum++;
            }
        }

        // 修改数据
        gameData.setScene13Count(scene13Count);
    }

    // -------------------- 【同色消除后】 --------------------

    private static void scene_09_afterSameColorEliminate(WasheConfig config, WasheGameData gameData, Set<WasheBlock> roundEliminateSet, WasheOperateStageResult stageResult, eWasheOperateType operateType) {

        // 卡片不能消除框
        if (operateType != eWasheOperateType.Move && operateType != eWasheOperateType.UseSkill) {
            return;
        }

        List<List<WasheBlock>> blockList = gameData.getBlockList();
        Map<Integer, Map<Integer, WasheBlock>> frameMap = gameData.getFrameMap();

        List<WasheBlock> changeList = new ArrayList<>();
        for (WasheBlock block : roundEliminateSet) {
            Map<Integer, WasheBlock> map = frameMap.get(block.getY());
            if (map != null) {
                WasheBlock frame = map.get(block.getX());
                if (frame != null && frame.getBlockType() == eWasheBlockType.DianShanLeiMing) {
                    if (WasheGameLogic.canSameColorEliminate(blockList, block)) {

                        // 消除框
                        map.remove(frame.getX());
                        changeList.add(frame);
                        // 设置加步数效果
                        stageResult.getAddStepBlockList().add(frame);

                    }
                }
            }
        }

        roundEliminateSet.addAll(changeList);
    }

    private static void scene_10_afterSameColorEliminate(WasheConfig config, WasheGameData gameData, Set<WasheBlock> roundEliminateSet, WasheOperateStageResult stageResult, eWasheOperateType operateType) {

        // 卡片不能消除框
        if (operateType != eWasheOperateType.Move && operateType != eWasheOperateType.UseSkill) {
            return;
        }

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.YiBenWanLi.getType());
        int multi = sceneConfig.getParamList().get(0).intValue();

        // 拿格子
        List<WasheBlock> frameList = new ArrayList<>();
        List<List<WasheBlock>> blockList = gameData.getBlockList();
        Map<Integer, Map<Integer, WasheBlock>> frameMap = gameData.getFrameMap();
        for (WasheBlock block : roundEliminateSet) {
            if (frameMap.containsKey(block.getY()) && frameMap.get(block.getY()).containsKey(block.getX())) {
                if (WasheGameLogic.canSameColorEliminate(blockList, block)) {
                    frameList.add(frameMap.get(block.getY()).get(block.getX()));
                }
            }
        }
        if (frameList.isEmpty()) {
            return;
        }

        // 找消除组处理
        Map<Integer, List<List<WasheBlock>>> listMap = WasheCreateBombLogic.groupEliminateSet(roundEliminateSet);
        for (WasheBlock frame : frameList) {
            for (List<List<WasheBlock>> listList : listMap.values()) {
                for (List<WasheBlock> list : listList) {
                    boolean anyMatch = list.stream().anyMatch(item -> item.getX() == frame.getX() && item.getY() == frame.getY());
                    // 找到框所在消除组了
                    if (anyMatch) {
                        // 消除框
                        frameMap.get(frame.getY()).remove(frame.getX());
                        roundEliminateSet.add(frame);
                        // 同色消除的格子加效果    （可同色消除 + 只能有一个一本万利）
                        for (WasheBlock block : list) {
                            if (WasheGameLogic.canSameColorEliminate(blockList, block)) {
                                if (block.getEffectList().stream().noneMatch(item -> item.getEffectType() == eWasheBlockEffectType.MultiScore_Hide)) {
                                    WasheBlockEffect effect = new WasheBlockEffect(eWasheBlockEffectType.MultiScore_Hide);
                                    effect.setEffectValue(multi);
                                    block.addEffect(effect);
                                }
                            }
                        }
                    }
                }
            }
        }
    }


    // -------------------- 【玩家操作结束】 --------------------

    private static void scene_03_operateEnd(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result) {

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.LuoGuXuanTian.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int initScore = paramList.get(0).intValue();
        int addScore = paramList.get(1).intValue();

        Map<Integer, Map<Integer, WasheBlock>> frameMap = gameData.getFrameMap();
        List<WasheBlock> changeList = new ArrayList<>();

        // 未消除锣鼓加分
        if (result.getType() == eWasheOperateType.Move) {
            for (Map<Integer, WasheBlock> map : frameMap.values()) {
                for (WasheBlock frame : map.values()) {
                    if (frame.getBlockType() == eWasheBlockType.LuoGuXuanTian) {
                        for (WasheBlockEffect effect : frame.getEffectList()) {
                            if (effect.getEffectType() == eWasheBlockEffectType.LuoGuXuanTian) {
                                effect.setEffectValue(effect.getEffectValue() + addScore);
                            }
                        }
                        changeList.add(frame);
                    }
                }
            }
        }

        // 已消除锣鼓重置
        for (Map<Integer, WasheBlock> map : frameMap.values()) {
            for (WasheBlock frame : map.values()) {
                if (frame.getBlockType() == eWasheBlockType.LuoGuXuanTian_Del) {

                    // 移除旧的
                    map.remove(frame.getX());

                    // 添加新的
                    WasheBlockEffect effect = new WasheBlockEffect(eWasheBlockEffectType.LuoGuXuanTian);
                    effect.setEffectValue(initScore);
                    WasheBlock tmpFrame = WasheBlock.createFrame(frame.getX(), frame.getY(), eWasheBlockType.LuoGuXuanTian);
                    tmpFrame.addEffect(effect);
                    gameData.addFrame(tmpFrame);

                    changeList.add(frame);
                }
            }
        }

        if (changeList.size() > 0) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.UpdateBlock);
            effect.setBlockList(changeList);
            result.addEffect(effect);
        }
    }

    private static void scene_07_operateEnd(WasheGameData gameData, WasheOperateResult result) {
        // 暂存宝箱打开
        if (!gameData.getScene07StageBoxList().isEmpty()) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.OpenStageBox);
            effect.setBlockList(gameData.getScene07StageBoxList());
            result.addEffect(effect);

            // 清空
            gameData.setScene07StageBoxList(new ArrayList<>());
        }
    }

    private static void scene_12_operateEnd(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result, boolean checkCanChange) {

        if (checkCanChange && !scene_12_canChange(result)) {
            return;
        }

        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(eWasheSceneType.WuCaiBinFen.getType());
        List<Long> paramList = sceneConfig.getParamList();
        int minAddScore = paramList.get(0).intValue();
        int maxAddScore = paramList.get(1).intValue();

        List<List<WasheBlock>> blockList = gameData.getBlockList();

        // 选择颜色
        int scene12Color = gameData.getScene12Color();
        if (scene12Color == 0) {
            scene12Color = random.nextInt(6 - 2) + 3; // 共6色，排除红蓝2色
        }
        scene12Color = (scene12Color - 3 + 1) % 4 + 3; // 切换到下一种颜色

        // 随机分数
        int score = random.nextInt(maxAddScore - minAddScore) + minAddScore;

        // 记录数据
        gameData.setScene12Color(scene12Color);
        gameData.setScene12Score(score);

        // 效果变化
        Set<WasheBlock> changeSet = new HashSet<>();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (scene_12_checkEffectChange(block, gameData)) {
                    changeSet.add(block);
                }
            }
        }

        // 添加效果
        if (!changeSet.isEmpty()) {
            WasheOperateEffect effect = new WasheOperateEffect(eWasheEffectType.UpdateBlock);
            effect.setBlockList(new ArrayList<>(changeSet));
            result.addEffect(effect);
        }
    }

    // -------------------- 【消除结束】 --------------------

    public static void scene_07_eliminateEnd(WasheConfig config, Random random, WasheGameData gameData, WasheOperateResult result, WasheUserGameData userGameData, int roomRound, int turnPlayer) {
        for (int times = 0; times < 50; times++) {

            List<WasheBlock> changeList = new ArrayList<>();
            List<List<WasheBlock>> blockList = gameData.getBlockList();
            List<WasheBlock> list = blockList.get(0);
            for (int i = 0; i < list.size(); i++) {
                WasheBlock block = list.get(i);
                if (block.getBlockType() == eWasheBlockType.BaiBaoXiang) {
                    list.set(i, null);
                    changeList.add(block);
                }
            }
            if (changeList.isEmpty()) {
                break;
            }

            // 设置加蓝
            int addMp = config.getSceneConfigMap().get(eWasheSceneType.BaiBaoXiang.getType()).getParamList().get(0).intValue();
            for (WasheBlock block : changeList) {
                block.setSp(addMp);
                result.setScene07AddMp(result.getScene07AddMp() + addMp);
            }

            // 加效果
            eWasheEffectType effectType = eWasheEffectType.OpenBox;
            if (result.getType() == eWasheOperateType.UseCard) {
                gameData.getScene07StageBoxList().addAll(changeList);
                effectType = eWasheEffectType.StageBox;
            }
            WasheOperateEffect effect = new WasheOperateEffect(effectType);
            effect.setBlockList(changeList);
            result.addEffect(effect);

            // 掉落方块
            WasheGameLogic.dropBlock(config, blockList, random, -1, gameData, roomRound, turnPlayer);
            WasheOperateRoundResult roundResult = new WasheOperateRoundResult();
            roundResult.setGameData(gameData.clone());
            result.addRoundResult(roundResult);

            // 继续消除
            WasheGameLogic.eliminate(config, gameData, userGameData, null, new HashSet<>(), result, random, -1, roomRound, turnPlayer);
        }
    }


    // -------------------- 【其他】 --------------------

    public static int scene_06_getEliminateNum(WasheConfig config) {
        return config.getSceneConfigMap().get(eWasheSceneType.GuiKeZhanBu.getType()).getParamList().get(2).intValue();
    }

    public static int scene_07_checkChooseBlock(WasheUseSkillParam skillParam, WasheGameData gameData, boolean checkTo) {
        if (gameData.getSceneId() != eWasheSceneType.BaiBaoXiang.getType()) {
            return 0;
        }

        List<Integer> xList = new ArrayList<>();
        List<Integer> yList = new ArrayList<>();
        xList.add(skillParam.getX());
        yList.add(skillParam.getY());
        if (checkTo) {
            xList.add(skillParam.getToX());
            yList.add(skillParam.getToY());
        }

        List<List<WasheBlock>> blockList = gameData.getBlockList();
        for (int i = 0; i < xList.size(); i++) {
            int x = xList.get(i);
            int y = yList.get(i);
            if (!WasheGameLogic.isXyExist(blockList, x, y)) {
                return GameErrorCode.E_WASHE_POS_NO_EXIST;
            }
            if (blockList.get(y).get(x).getBlockType() == eWasheBlockType.BaiBaoXiang) {
                return GameErrorCode.E_WASHE_CAN_NOT_CHOOSE;
            }
        }

        return 0;
    }

    public static void scene_07_removeBox(Set<WasheBlock> set) {
        List<WasheBlock> removeList = new ArrayList<>();
        for (WasheBlock block : set) {
            if (block.getBlockType() == eWasheBlockType.BaiBaoXiang) {
                removeList.add(block);
            }
        }
        set.removeAll(removeList);
    }

    public static void scene_08_fixColor(WasheGameData gameData, WasheOperateResult result) {
        if (gameData.getSceneId() != eWasheSceneType.HongYouQingHua.getType()) {
            return;
        }

        int blue = result.getTurn() == 1 ? eWasheColorType.Red.getValue() : eWasheColorType.Blue.getValue();
        int red = result.getTurn() == 1 ? eWasheColorType.Blue.getValue() : eWasheColorType.Red.getValue();

        // 先全部变蓝色
        Set<WasheBlock> changeSet1 = new HashSet<>();
        List<List<WasheBlock>> blockList = gameData.getBlockList();
        for (List<WasheBlock> list : blockList) {
            for (WasheBlock block : list) {
                if (block.getBlockType() == eWasheBlockType.HongYouQingHua) {
                    block.setColor(blue);
                    changeSet1.add(block);
                }
            }
        }

        // 蓝色无法消除的全部变红色
        Set<WasheBlock> changeSet2 = new HashSet<>();
        for (WasheBlock block : changeSet1) {
            if (!WasheGameLogic.canSameColorEliminate(blockList, block)) {
                block.setColor(red);
                changeSet2.add(block);
            }
        }

        // 红色无法消除的变回蓝色
        for (WasheBlock block : changeSet2) {
            if (!WasheGameLogic.canSameColorEliminate(blockList, block)) {
                block.setColor(blue);
            }
        }
    }

    public static void scene_08_changeColor(WasheGameData gameData, int color) {
        if (gameData.getSceneId() != eWasheSceneType.HongYouQingHua.getType()) {
            return;
        }
        if (color != eWasheColorType.Red.getValue() && color != eWasheColorType.Blue.getValue()) {
            return;
        }

        for (List<WasheBlock> list : gameData.getBlockList()) {
            for (WasheBlock block : list) {
                if (block.getBlockType() == eWasheBlockType.HongYouQingHua) {
                    block.setColor(color);
                }
            }
        }
    }

    public static int scene_09_getAddStepNum(WasheConfig config) {
        return config.getSceneConfigMap().get(eWasheSceneType.DianShanLeiMing.getType()).getParamList().get(2).intValue();
    }

    public static boolean scene_12_checkEffectChange(WasheBlock block, WasheGameData gameData) {
        if (gameData.getSceneId() == eWasheSceneType.WuCaiBinFen.getType()) {
            List<WasheBlockEffect> effectList = block.getEffectList();

            if (block.getColor() == gameData.getScene12Color() &&
                    (block.getBlockType().getBigType() == eWasheBlockType.BIG_TYPE_NORMAL || block.getBlockType().getBigType() == eWasheBlockType.BIG_TYPE_NORMAL_BOMB)) {
                // 添加
                if (effectList.stream().noneMatch(item -> item.getEffectType() == eWasheBlockEffectType.WuCaiBinFen)) {
                    WasheBlockEffect effect = new WasheBlockEffect(eWasheBlockEffectType.WuCaiBinFen);
                    effect.setEffectValue(gameData.getScene12Score());
                    block.addEffect(effect);
                    return true;
                }
            } else {
                // 移除
                boolean change = false;
                for (int i = 0; i < effectList.size(); i++) {
                    if (effectList.get(i).getEffectType() == eWasheBlockEffectType.WuCaiBinFen) {
                        effectList.remove(i--);
                        change = true;
                    }
                }
                return change;
            }
        }
        return false;
    }

    private static boolean scene_12_canChange(WasheOperateResult result) {
        for (WasheOperateShow show : result.getShowList()) {
            for (WasheOperateRoundResult roundResult : show.getRoundResultList()) {
                for (WasheOperateStageResult stageResult : roundResult.getStageResultList()) {
                    for (WasheBlock block : stageResult.getEliminateList()) {
                        for (WasheBlockEffect effect : block.getEffectList()) {
                            if (effect.getEffectType() == eWasheBlockEffectType.WuCaiBinFen) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

}
